import java.awt.Point;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

public class SelectionEventProcessor extends DrawObjectEventProcessor
{
    // CALL METHODS OF THIS "SELECTION" EVENT PROCESSOR EARLY!
    // (sets some flags and objects required by the specialized DrawObjectEventProcessors!)

    @Override
    public void TryProcessUserKeyboardAction(MainWindow.GUIElements GUIElements, KeyEventProcessor KeyEventProcessor, MouseEventProcessor MouseEventProcessor, ObjectStorage ObjectStorage, IOProgram IOProgram)
    {
        if (!(KeyboardEventsToBeProcessed(GUIElements)))
            return;

        // ****************************************************************
        // ESC (end multi-selection)
        if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_ESCAPE))
        {
            if (MultiSelectionExisting)
            {
                MultiSelectionExisting = false;

                Selection = UNDEFINED_SELECTION;

                ObjectStorage.UnHighlightAllObjects();
                ObjectStorage.UnSetPartOfMultiSelectionForAllObjects();

                GUIElements.GetMainWindow().DoRedraw();
            }
        }

        return;
    }

    @Override
    public void TryProcessUserMouseAction(MainWindow.GUIElements GUIElements, KeyEventProcessor KeyEventProcessor, MouseEventProcessor MouseEventProcessor, ObjectStorage ObjectStorage, IOProgram IOProgram)
    {
        if (!(MouseEventsToBeProcessed(GUIElements)))
            return;

        if (MouseEventProcessor.IsMouseMoved() &&
            NOT(MouseEventProcessor.AnyButtonPressed()))
        {
            SingleSelectedObjectOffset = null;
        }

        // ****************************************************************
        if (NOT(MouseEventProcessor.IsMouseDragged()) &&
            MouseEventProcessor.AnyButtonPressed())
        {
            DrawObject SingleSelectedObjectOld = SingleSelectedObject;

            SingleSelectedObject = ObjectStorage.TrySelectDrawObject(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

            if (DEFINED(SingleSelectedObject))
            {
                if (SingleSelectedObject != SingleSelectedObjectOld)
                {
                    GUIElements.GetMainWindow().DoRedraw();
                }
            }
        }
        // ****************************************************************
        if (MouseEventProcessor.IsLeftButtonDown())
        {
            if (DEFINED(SingleSelectedObject) &&
                UNDEFINED(SingleSelectedObjectOffset))
            {
                SingleSelectedObjectOffset = Tools.SubtractPoints(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())), SingleSelectedObject.Pos);
            }
        }
        // ****************************************************************
        if (MouseEventProcessor.IsLeftButtonDown() &&
            NOT(KeyEventProcessor.IsControlPressed()) &&
            KeyEventProcessor.IsShiftPressed()) // Shift and Control at the same time is currently not supported
        {
            if (UNDEFINED(Selection))
            {
                ObjectStorage.UnSetPartOfMultiSelectionForAllObjects(); // do this to avoid any confusion of system ;-P

                NearObject = UNDEFINED;

                SingleSelectedObject = UNDEFINED;
                SingleSelectedObjectOffset = UNDEFINED_POINT;

                Selection = new Selection(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));
                Selection.SetEndPoint(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

                ObjectStorage.AddObjectDirectly(Selection);

                GUIElements.GetMainWindow().DoRedraw();
            }
            else
            {
                Point EndPointNew = DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()));
                if (EndPointNew != Selection.GetEndPoint())
                {
                    Selection.SetEndPoint(EndPointNew);

                    ArrayList<DrawObject> MultiSelectionObjects = ObjectStorage.GetSelectionObjects(Selection.Pos, Selection.Size);

                    ObjectStorage.UnSetPartOfMultiSelectionForAllObjects();

                    for (int i = 0; i < MultiSelectionObjects.size(); i++)
                    {
                        MultiSelectionObjects.get(i).SetPartOfMultiSelection(true);
                    }

                    GUIElements.GetMainWindow().DoRedraw();
                }
            }

            MoveMousePosLast = UNDEFINED_POINT; // no button pressed, no moving!
        }
        // ****************************************************************
        if (MouseEventProcessor.IsLeftButtonDown() &&
            KeyEventProcessor.IsControlPressed() &&
            NOT(KeyEventProcessor.IsShiftPressed())) // Shift and Control at the same time is currently not supported
        {
            if (DEFINED(SingleSelectedObject))
            {
                if (SingleSelectedObject.CanBeSelectedByUser())
                {
                    if (NOT(SingleSelectedObject.IsPartOfMultiSelection()))
                    {
                        SingleSelectedObject.SetPartOfMultiSelection(true);

                        GUIElements.GetMainWindow().DoRedraw();
                    }
                    else
                    {
                        SingleSelectedObject.SetPartOfMultiSelection(false);

                        GUIElements.GetMainWindow().DoRedraw();
                    }
                }
            }

            if (DEFINED(MoveMousePosLast))
            {
                Point MousePosLastAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MoveMousePosLast));
                Point MousePosAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

                if (MousePosAligned.x != MousePosLastAligned.x || MousePosAligned.y != MousePosLastAligned.y)
                {
                    ObjectStorage.MoveMultiSelection(Tools.SubtractPoints(MousePosAligned, MousePosLastAligned));

                    GUIElements.GetMainWindow().DoRedraw();
                }
            }

            MoveMousePosLast = MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()); // do NOT zoom!
        }
        // ****************************************************************
        if (MouseEventProcessor.IsLeftButtonDown() &&
            NOT(KeyEventProcessor.IsControlPressed()) &&
            NOT(KeyEventProcessor.IsShiftPressed()))
        {
            if (MultiSelectionExisting)
            {
                if (DEFINED(MoveMousePosLast))
                {
                    Point MousePosLastAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MoveMousePosLast));
                    Point MousePosAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

                    if (MousePosAligned.x != MousePosLastAligned.x || MousePosAligned.y != MousePosLastAligned.y)
                    {
                        ObjectStorage.MoveMultiSelection(Tools.SubtractPoints(MousePosAligned, MousePosLastAligned));

                        GUIElements.GetMainWindow().DoRedraw();
                    }
                }
            }
            else if (DEFINED(SingleSelectedObject))
            {
                if (SingleSelectedObject.CanBeMovedByUser())
                {
                    Point PosNew = // DO NOT ALIGN HERE! In tests, objects got moved when trying to draw Lines, if aligning PosNew!
                        Tools.SubtractPoints(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())), SingleSelectedObjectOffset);

                    if (PosNew.x != SingleSelectedObject.Pos.x || PosNew.y != SingleSelectedObject.Pos.y)
                    {
                        SingleSelectedObject.SetPos(PosNew);

                        LineStart = UNDEFINED;

                        GUIElements.GetMainWindow().DoRedraw();
                    }
                }
            }

            MoveMousePosLast = MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()); // do NOT zoom!
        }
        // ****************************************************************
        if (MouseEventProcessor.IsRightButtonDown())
        {
            if (DEFINED(MoveMousePosLast))
            {
                Point MousePosLastAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MoveMousePosLast));
                Point MousePosAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

                if (MousePosAligned.x != MousePosLastAligned.x || MousePosAligned.y != MousePosLastAligned.y)
                {
                    ObjectStorage.MoveAll(Tools.SubtractPoints(MousePosAligned, MousePosLastAligned));

                    if (DEFINED(Selection))
                    {
                        Selection.Move(Tools.SubtractPoints(MousePosAligned, MousePosLastAligned));
                    }

                    GUIElements.GetMainWindow().DoRedraw();
                }
            }

            MoveMousePosLast = MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()); // do NOT zoom!
        }
        // ****************************************************************
        if (MouseEventProcessor.NoButtonPressed())
        {
            if (DEFINED(Selection)) // delete selection rect if mouse button released
            {
                ObjectStorage.DeleteObject(Selection);

                Selection = UNDEFINED_SELECTION;

                GUIElements.GetMainWindow().DoRedraw();
            }
        }

        // ****************************************************************
        String SelectionInfoText = "ESC to deselect";
        if (MultiSelectionExisting)
        {
            GUIElements.GetMainWindow().GetTitleBarInfo().AddInfoText(SelectionInfoText, false, false, true, false); // show progress to make sure user realized he must do something with selection
        }
        else
        {
            GUIElements.GetMainWindow().GetTitleBarInfo().RemoveInfoText(SelectionInfoText);
        }

        return;
    }
}
